#include "device.h"
#include "../msg/msg.h"
#include "../input/input.h"
#include "../../project/nav_view.h"

#include <stdlib.h>
#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>

#include <view.h>
#include <types.h>
#include <macro.h>
#include <jpeg/jpeglib.h>

int device::left	= 0;
int device::top		= 0;
int device::width	= 0;
int device::right	= 0;
int device::bottom	= 0;
int device::fd		= -1;
int device::zk		= -1;
unsigned char * device::buf_zk=NULL;
int device::zk_len      = -1;
#ifdef COLOR32
unsigned int * device::bitbuf   = NULL;
#else
unsigned short * device::bitbuf = NULL;
#endif

#ifdef LINUX_CONSOLE
struct termios device::old;
#endif
nav_view device::nav;


int device::init(){
        struct fb_var_screeninfo vinfo;
        struct fb_fix_screeninfo finfo;
        unsigned char buf[50];
	int ret=0;

        fd =open(FB_PATH,O_RDWR);
        if(fd<0){
                //------------
                return -1;
        }

        if (ioctl(fd,FBIOGET_FSCREENINFO,&finfo)){
                printf("Error reading fixed information\n");
                return -1;
        }

        if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo)) {
                //printf("Error reading variable information.\n");
                return -1;
        }

        left            = 0;
        top             = 0;
        right           = vinfo.xres;
        bottom          = vinfo.yres;
#ifdef COLOR32
        width		= finfo.line_length/4;
#else
        width 		= finfo.line_length/2;
#endif

#ifdef COLOR32
        bitbuf=(unsigned int *)mmap(buf,width*bottom*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(NULL==bitbuf){
                printf("===Map FB device failed===\n");
                return -1;
        }
        //memset(bitbuf,0xff,width*bottom*4);
#else
        bitbuf=(unsigned short *)mmap(buf,width*bottom*2,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
        if(NULL==bitbuf){
                printf("===Map FB device failed===\n");
                return -1;
        }
        //memset(bitbuf,0xf,right*bottom*2);
        #endif

        zk =open(ZK_PATH,O_RDWR);
        if(zk<0){
                //------------
                return -1;
        }
        lseek(zk,0,SEEK_SET);
        zk_len=lseek(zk,0,SEEK_END);

        buf_zk=(unsigned char *)mmap(NULL,zk_len,PROT_READ|PROT_WRITE,MAP_SHARED,zk,0);
        if(buf_zk==NULL){
                //printf("map device failed\n");
                return -1;
        }

	#ifdef LINUX_CONSOLE
	ret=init_console();
	#endif

	nav.init(left,top,right,bottom,0);

	return ret;
};

int device::exit(){
	int ret=0;
        #ifdef COLOR32
        munmap(bitbuf,width*bottom*4);
        #else
        munmap(bitbuf,width*bottom*2);
        #endif
        munmap(buf_zk,zk_len);
	close(fd);
	close(zk);
	#ifdef LINUX_CONSOLE
	ret=exit_console();
	#endif

	return ret;
};
device::device(){init();};
device::~device(){/*
        #ifdef COLOR32
        munmap(bitbuf,width*bottom*4);
        #else
        munmap(bitbuf,width*bottom*2);
        #endif
        munmap(buf_zk,zk_len);
	close(fd);
	close(zk);*/
	exit();
};

#ifdef COLOR32
void device::draw_string(char *tt,int x,int y,unsigned int color){
#else
void device::draw_string(char *tt,int x,int y,unsigned short color){
#endif
        unsigned char buf[ZK_BIT_LEN];
        unsigned int zz;
        int offset;
        int i,j,k;
        int xx=x;
        int hz_flag=0;
        unsigned char *tmp;
        unsigned char *t=(unsigned char *)tt;

        while(*t){
                if(*t<128){
                        hz_flag=0;
                        if((*t>='0')&&(*t<='9')){
                                offset=203+*t-'0';
                                offset=offset*32;
                        }else if((*t>='A')&&(*t<='Z')){
                                offset=220+*t-'A';
                                offset=offset*32;
                        }else if((*t>='a')&&(*t<='z')){
                                offset=252+*t-'a';
                                offset=offset*32;
                        }
                }else{
                        offset=((*t - 0xa0)-1)*94;
                        t++;
                        offset=offset+*t-0xa0-1;
                        offset=offset*ZK_BIT_LEN;
                        hz_flag=1;
                }
                tmp=buf_zk+offset;
                k=device::width*y;

                for(i=0;i<ZK_BITS;i++){
                        zz=*tmp++;
                        zz=(zz<<8)|*tmp++;
                        for(j=(ZK_BITS-1);j>=0;j--){
                                if((zz>>j)&1)
                                        bitbuf[k+xx]=color;
                                else
                                        //buf_fb[k+xx]=0xffffff;
                                        ;
                                k++;
                        }
                        k=device::width*(i+y);
                }
                t++;
                if(hz_flag)
                        xx=xx+ZK_BITS;
                else    xx=xx+ZK_BITS-3;
        }

};

#ifdef COLOR32
void device::draw_line(int l,int t,int len,enum LINE_TYPE type,unsigned int color){
#else
void device::draw_line(int l,int t,int len,enum LINE_TYPE type,unsigned short color){
#endif
	int i,j;
	//printf("l:%d t:%d len:%d\n",l,t,len);
	if(type==LINE_H){
		j=l+len;
		for(i=l;i<j;i++)
			bitbuf[t*width+i]=color;
			//printf("offset:%d\n",t*device::right+i);
	}else if(type==LINE_V){
		j=t+len;
		for(i=t;i<j;i++)
			bitbuf[i*width+l]=color;
			//printf("i:%d right:%d l:%d\n",i,device::right,l);
	}

};


#ifdef COLOR32
void device::draw_rect(int l,int t,int r,int b,unsigned int color){
#else
void device::draw_rect(int l,int t,int r,int b,unsigned short color){
#endif
	int i,j;
	int len;

	len=r-l;
	draw_line(l,t,len,LINE_H,color);
	draw_line(l,b,len,LINE_H,color);
	len=b-t;
	draw_line(l,t,len,LINE_V,color);
	draw_line(r,t,len,LINE_V,color);

};


#ifdef COLOR32
void device::fill_rect(int l,int t,int r,int b,unsigned int color){
#else
void device::fill_rect(int l,int t,int r,int b,unsigned short color){
#endif
	int i=l;
	for(;i<r;i++)
		draw_rect(i,t,r,b,color);
};

#ifdef LINUX_CONSOLE
int device::init_console(){
	int ret=0;
        struct termios raw;
        tcgetattr(0,&old);

        tcgetattr(0,&raw);
        cfmakeraw(&raw);

        ret=tcsetattr(0,TCSANOW,&raw);
	return ret;
};
int device::exit_console(){
	int ret=0;
	ret = tcsetattr(0,TCSANOW,&old);
	return ret;
};
#endif

int device::draw_jpg(int l,int t,char *filename){
        struct jpeg_decompress_struct cinfo;
        struct jpeg_error_mgr jerr;
        FILE *infile;
        unsigned char  *buffer;
        int x, y;

        unsigned char *tmp_buf;
        unsigned long size;
        int ret;

         if((infile = fopen(filename, "rb")) == NULL){
                printf("read file:%s error\n",filename);
                return -1;
        }

        cinfo.err = jpeg_std_error(&jerr);
        jpeg_create_decompress(&cinfo);

        fseek(infile, 0L, SEEK_END);
        size = ftell(infile);
        rewind(infile);

        tmp_buf = (unsigned char *)malloc(sizeof(char) * size);
        if (tmp_buf == NULL)
        {
                printf("malloc failed.\n");
                return -1;
        }
        ret = fread(tmp_buf, 1, size, infile);
        if (ret != size)
        {
                printf("read jpeg file error.\n");
                return -1;
        }
	jpeg_mem_src(&cinfo, tmp_buf, size);
        jpeg_read_header(&cinfo, TRUE);
        jpeg_start_decompress(&cinfo);
        if ((cinfo.output_width > (right-l)) || (cinfo.output_height > (bottom-t))) {
                printf("too large JPEG file,cannot display\n");
                return -1;
        }
	
	buffer = (unsigned char *) malloc(cinfo.output_width * cinfo.output_components);
        x = y = 0;
	
	#ifdef COLOR32
	unsigned int color;
	#else
	unsigned short color;
	#endif

	while (cinfo.output_scanline < cinfo.output_height) {
                jpeg_read_scanlines(&cinfo, &buffer, 1);
                for(x=0;x<cinfo.output_width;x++){
			#ifdef COLOR32
                        color=buffer[x*3+2]|(buffer[x*3+1]<<8)|(buffer[x*3]<<16);
			#else
			color=RGB565(buffer[x*3+2],buffer[x*3+1],buffer[x*3]);
			#endif
                        bitbuf[(y+top)*1408+x+l]=color;
                }
                y++;        // next scanline
        }

	fclose(infile);
        free(tmp_buf);
	free(buffer);
};

int device::message(msg *m){

	int ret=0;

	nav.key_down_proc(m);
};
